// Licensed under the Mulan PSL v2.
// You can use this file according to the terms and conditions of the Mulan PSL v2.
// You may obtain a copy of the License at
//
//     http://license.coscl.org.cn/MulanPSL2
//
// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
// EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. SEE THE MULAN PSL v2
// FOR MORE DETAILS.

#include "Import/BDFImport/BulkData/Design/DDVALParser.h"

#include <algorithm>
#include <cstdint>
#include <iostream>

#include "Utility/Exception/SGException.h"
#include "Utility/Logging/SGLogger.h"

#include "DataStructure/Input/Design/DDVALData.h"

#include "DBManager/DBServiceFactory.h"
#include "DBManager/IService/Input/Design/IDDVALService.h"

#include "Import/BDFImport/BDFParserBase.h"

BULKDATA_ENTRY_PARSER_REG (DDVAL);

using namespace SG::DBManager;
using namespace SG::Import;
using namespace SG::DataStructure;
using namespace SG::DataStructure::Common;

Status BDF::BULKDATA::ParseDDVAL (const std::shared_ptr<SG::DBManager::DBServiceFactory>& dbServiceFactory,
                                  std::vector<std::string>&                               dividedEntryInfo)
{
    SG::DataStructure::FEM::DDVALData tempData;  // 创建临时的DLINK数据对象

    // 解析id
    tempData.m_id = convertToI64 (dividedEntryInfo[1]);

    // 计算词条行数
    size_t const rowNum = dividedEntryInfo.size () / 10;
    // 设置续行符下标
    size_t const endColumnIndex = 9;
    // 节点的第一行从index=2开始
    size_t beginColumnIndex = 2;
    // 节点第一行的THURColumnIndex
    size_t THURColumnIndex = 3;

    // 解析DVALi
    for (size_t curRow = 0; curRow < rowNum; curRow++)
    {
        // 首先判断是不是第一行
        if (curRow != 0)
        {
            beginColumnIndex = 1;
            THURColumnIndex  = 2;
        }

        const size_t thurIndex = (curRow * 10) + THURColumnIndex;

        // 判断是否是THUR BY行,所有THUR关键字index在3（第一行）或者2（续行）,即该行不允许前面空 中间空
        if (boost::iequals (dividedEntryInfo[thurIndex], "THRU") && boost::iequals (dividedEntryInfo[thurIndex + 2], "BY"))
        {
            // 获取start end step的字段
            std::string& startStrKey = dividedEntryInfo[thurIndex - 1];
            std::string& endStrKey   = dividedEntryInfo[thurIndex + 1];
            std::string& stepStrKey  = dividedEntryInfo[thurIndex + 3];
            // 转化成real
            const Real startReal = convertToReal (startStrKey);
            const Real endReal   = convertToReal (endStrKey);
            const Real stepReal  = convertToReal (stepStrKey);

            // 解析start end step逻辑语句，并存入tempData
            // 由stepReal判断方向
            if (stepReal > 0.0)
            {
                if (startReal > endReal)
                {
                    throw SG::Utility::ValueError ("DDVAL: start value is greater than end value when step is positive.");
                }
                // 写成num < endReal+stepReal而非num < endReal的原因是词条解释：DDVAL包含end值，即使start到end的范围不能被step整除
                for (Real num = startReal; num < endReal + stepReal; num += stepReal)
                {
                    tempData.m_DVALList.emplace_back (num);
                }
            }
            else if (stepReal < 0.0)
            {
                if (startReal < endReal)
                {
                    throw SG::Utility::ValueError ("DDVAL: start value is less than end value when step is negative.");
                }
                // 当stepReal<0时，与上面类似，只用调整相反即可
                for (Real num = startReal; num > endReal + stepReal; num += stepReal)
                {
                    tempData.m_DVALList.emplace_back (num);
                }
            }
            else
            {
                // step = 0 跳过该句，读下一行
                continue;
            }
        }
        else
        {
            // 逐个写入，遇空则跳
            for (size_t fieldsColumn = beginColumnIndex; fieldsColumn < endColumnIndex; fieldsColumn++)
            {
                // 计算当前字段的索引
                const size_t curIndex = (curRow * 10) + fieldsColumn;
                // 获取当前字段
                std::string& curStrKey = dividedEntryInfo[curIndex];
                // 若空白则跳过
                if (is_all_space (curStrKey))
                {
                    continue;
                }
                // 插入到tempData中
                tempData.m_DVALList.emplace_back (convertToReal (curStrKey));
            }
        }
    }

    return dbServiceFactory->get<IDDVALService> ()->Add (tempData);
}